#include "bt.h"

#include "hc05.h"
#include "stm32f1xx_hal.h"

#undef Handler
#define Handler Bt_HandleTypeDef*

#undef handler
#define handler (**(Bt_HandleTypeDef**)&handle)

Bt_HandleTypeDef hbt;

void Bt_Init(void M_L(void*), void M_W(void*), void M_J(void*),
             void M_O(void*),  // M
             void U_L(void*), void U_W(void*), void U_J(void*),
             void U_O(void*),  // U
             void D_L(void*), void D_W(void*), void D_J(void*),
             void D_O(void*),  // D
             void L_L(void*), void L_W(void*), void L_J(void*),
             void L_O(void*),  // L
             void R_L(void*), void R_W(void*), void R_J(void*),
             void R_O(void*),  // R
             uint32_t my_speed) {
  // 将是否使主调函数退出设为0
  // 将cache和state都设为零
  hbt.bu &= BU_M;
  // 将长按的上一次执行时间设为0
  hbt.time.lp = 0;
  // 将hist设为0
  hbt.hist = HIST_N;
  // 将speed设为100
  if (my_speed) hbt.speed = my_speed;
  // 将task设为传入的参数
  hbt.task.M_L = (void (*)(void*))M_L;
  hbt.task.M_W = (void (*)(void*))M_W;
  hbt.task.M_J = (void (*)(void*))M_J;
  hbt.task.M_O = (void (*)(void*))M_O;
  hbt.task.U_L = (void (*)(void*))U_L;
  hbt.task.U_W = (void (*)(void*))U_W;
  hbt.task.U_J = (void (*)(void*))U_J;
  hbt.task.U_O = (void (*)(void*))U_O;
  hbt.task.D_L = (void (*)(void*))D_L;
  hbt.task.D_W = (void (*)(void*))D_W;
  hbt.task.D_J = (void (*)(void*))D_J;
  hbt.task.D_O = (void (*)(void*))D_O;
  hbt.task.L_L = (void (*)(void*))L_L;
  hbt.task.L_W = (void (*)(void*))L_W;
  hbt.task.L_J = (void (*)(void*))L_J;
  hbt.task.L_O = (void (*)(void*))L_O;
  hbt.task.R_L = (void (*)(void*))R_L;
  hbt.task.R_W = (void (*)(void*))R_W;
  hbt.task.R_J = (void (*)(void*))R_J;
  hbt.task.R_O = (void (*)(void*))R_O;
}

inline void Bt_Update(void) {
  hbt.time.now = HAL_GetTick();
  if ((hbt.bu & BU_M_M) !=
      (!HAL_GPIO_ReadPin(BUTTON_M_GPIO_Port, BUTTON_M_Pin) || hhc.M)) {
    hbt.bu ^= BU_M_M;
    hbt.time.m = hbt.time.now;
  }
  if ((hbt.bu & BU_M_U) >> 1 !=
      (!HAL_GPIO_ReadPin(BUTTON_U_GPIO_Port, BUTTON_U_Pin) || hhc.U)) {
    hbt.bu ^= BU_M_U;
    hbt.time.u = hbt.time.now;
  }
  if ((hbt.bu & BU_M_D) >> 2 !=
      (!HAL_GPIO_ReadPin(BUTTON_D_GPIO_Port, BUTTON_D_Pin) || hhc.D)) {
    hbt.bu ^= BU_M_D;
    hbt.time.d = hbt.time.now;
  }
  if ((hbt.bu & BU_M_L) >> 3 !=
      (!HAL_GPIO_ReadPin(BUTTON_L_GPIO_Port, BUTTON_L_Pin) || hhc.L)) {
    hbt.bu ^= BU_M_L;
    hbt.time.l = hbt.time.now;
  }
  if ((hbt.bu & BU_M_R) >> 4 !=
      (!HAL_GPIO_ReadPin(BUTTON_R_GPIO_Port, BUTTON_R_Pin) || hhc.R)) {
    hbt.bu ^= BU_M_R;
    hbt.time.r = hbt.time.now;
  }
}

void Bt_Run(void* handle) {
  static uint32_t lt = 0;

  if (hbt.bu & BU_M_M) {
    if (hbt.time.now - hbt.time.m > BT_LONG_TIME) {
      // M键已达到长按时间
      hbt.hist |= HIST_L;
    } else if (hbt.time.now - hbt.time.m > BT_WAIT_TIME) {
      // M键已达到等待时间
      if (!(hbt.hist & HIST_W) && hbt.task.M_W) {
        hbt.hist |= HIST_W;
        hbt.task.M_W(handle);
      }
    } else if (hbt.time.now - hbt.time.m > BT_JIT_TIME) {
      // M键已到达抖动时间
      hbt.bu |= BU_S_M;
      hbt.bu |= BU_C_M;
      if (!(hbt.hist & HIST_J) && hbt.task.M_J) {
        hbt.hist |= HIST_J;
        hbt.task.M_J(handle);
      }
    }
  } else if (hbt.time.now - hbt.time.m > BT_JIT_TIME) {
    // 按键松开后到达抖动时间
    hbt.bu &= ~BU_S_M;
    // 此处能保证只有当M键恰好松开时才执行任务
    if (hbt.bu & BU_C_M && hbt.task.M_O) hbt.task.M_O(handle);
  }

  if (hbt.bu & BU_M_U) {
    if (hbt.time.now - hbt.time.u > BT_LONG_TIME) {
      // U键已达到长按时间
      hbt.hist = HIST_L;
    } else if (hbt.time.now - hbt.time.u > BT_WAIT_TIME) {
      // U键已达到等待时间
      if (!(hbt.hist & HIST_W) && hbt.task.U_W) {
        hbt.hist |= HIST_W;
        hbt.task.U_W(handle);
      }
    } else if (hbt.time.now - hbt.time.u > BT_JIT_TIME) {
      // U键已到达抖动时间
      hbt.bu |= BU_S_U;
      hbt.bu |= BU_C_U;
      if (!(hbt.hist & HIST_J) && hbt.task.U_J) {
        hbt.hist |= HIST_J;
        hbt.task.U_J(handle);
      }
    }
  } else if (hbt.time.now - hbt.time.u > BT_JIT_TIME) {
    // 按键松开后到达抖动时间
    hbt.bu &= ~BU_S_U;
    if (hbt.bu & BU_C_U && hbt.task.U_O) hbt.task.U_O(handle);
  }

  if (hbt.bu & BU_M_D) {
    if (hbt.time.now - hbt.time.d > BT_LONG_TIME) {
      // D键已达到长按时间
      hbt.hist = HIST_L;
    } else if (hbt.time.now - hbt.time.d > BT_WAIT_TIME) {
      // D键已达到等待时间
      if (!(hbt.hist & HIST_W) && hbt.task.D_W) {
        hbt.hist |= HIST_W;
        hbt.task.D_W(handle);
      }
    } else if (hbt.time.now - hbt.time.d > BT_JIT_TIME) {
      // D键已到达抖动时间
      hbt.bu |= BU_S_D;
      hbt.bu |= BU_C_D;
      if (!(hbt.hist & HIST_J) && hbt.task.D_J) {
        hbt.hist |= HIST_J;
        hbt.task.D_J(handle);
      }
    }
  } else if (hbt.time.now - hbt.time.d > BT_JIT_TIME) {
    // 按键松开后到达抖动时间
    hbt.bu &= ~BU_S_D;
    if (hbt.bu & BU_C_D && hbt.task.D_O) hbt.task.D_O(handle);
  }

  if (hbt.bu & BU_M_L) {
    if (hbt.time.now - hbt.time.l > BT_LONG_TIME) {
      // L键已达到长按时间
      hbt.hist = HIST_L;
    } else if (hbt.time.now - hbt.time.l > BT_WAIT_TIME) {
      // L键已达到等待时间
      if (!(hbt.hist & HIST_W) && hbt.task.L_W) {
        hbt.hist |= HIST_W;
        hbt.task.L_W(handle);
      }
    } else if (hbt.time.now - hbt.time.l > BT_JIT_TIME) {
      // L键已到达抖动时间
      hbt.bu |= BU_S_L;
      hbt.bu |= BU_C_L;
      if (!(hbt.hist & HIST_J) && hbt.task.L_J) {
        hbt.hist |= HIST_J;
        hbt.task.L_J(handle);
      }
    }
  } else if (hbt.time.now - hbt.time.l > BT_JIT_TIME) {
    // 按键松开后到达抖动时间
    hbt.bu &= ~BU_S_L;
    if (hbt.bu & BU_C_L && hbt.task.L_O) hbt.task.L_O(handle);
  }

  if (hbt.bu & BU_M_R) {
    if (hbt.time.now - hbt.time.r > BT_LONG_TIME) {
      // R键已达到长按时间
      hbt.hist = HIST_L;
    } else if (hbt.time.now - hbt.time.r > BT_WAIT_TIME) {
      // R键已达到等待时间
      if (!(hbt.hist & HIST_W) && hbt.task.R_W) {
        hbt.hist |= HIST_W;
        hbt.task.R_W(handle);
      }
    } else if (hbt.time.now - hbt.time.r > BT_JIT_TIME) {
      // R键已到达抖动时间
      hbt.bu |= BU_S_R;
      hbt.bu |= BU_C_R;
      if (!(hbt.hist & HIST_J) && hbt.task.R_J) {
        hbt.hist |= HIST_J;
        hbt.task.R_J(handle);
      }
    }
  } else if (hbt.time.now - hbt.time.r > BT_JIT_TIME) {
    // 按键松开后到达抖动时间
    hbt.bu &= ~BU_S_R;
    if (hbt.bu & BU_C_R && hbt.task.R_O) hbt.task.R_O(handle);
  }

  // 以下是只有更新完所有按键状态后才能确定是否执行的任务
  if (!(hbt.bu & BU_S)) {
    // 此帧所有按键off
    hbt.bu &= ~BU_C;
    hbt.hist = HIST_N;
  } else if (hbt.hist == HIST_L) {
    if (lt + hbt.speed < hbt.time.now) {
      if ((hbt.bu & BU_S) == BU_S_U) {
        if (hbt.task.U_L) hbt.task.U_L(handle);
      } else if ((hbt.bu & BU_S) == BU_S_D) {
        if (hbt.task.D_L) hbt.task.D_L(handle);
      } else if ((hbt.bu & BU_S) == BU_S_L) {
        if (hbt.task.L_L) hbt.task.L_L(handle);
      } else if ((hbt.bu & BU_S) == BU_S_R) {
        if (hbt.task.R_L) hbt.task.R_L(handle);
      } else if (!(hbt.bu & BU_S_M)) {
        if (hbt.time.u > hbt.time.d) {
          if (hbt.time.u > hbt.time.l) {
            if (hbt.time.u > hbt.time.r) {
              if (hbt.task.U_L) hbt.task.U_L(handle);
            } else {
              if (hbt.task.R_L) hbt.task.R_L(handle);
            }
          } else {
            if (hbt.time.l > hbt.time.r) {
              if (hbt.task.L_L) hbt.task.L_L(handle);
            } else {
              if (hbt.task.R_L) hbt.task.R_L(handle);
            }
          }
        } else {
          if (hbt.time.d > hbt.time.l) {
            if (hbt.time.d > hbt.time.r) {
              if (hbt.task.D_L) hbt.task.D_L(handle);
            } else {
              if (hbt.task.R_L) hbt.task.R_L(handle);
            }
          } else {
            if (hbt.time.l > hbt.time.r) {
              if (hbt.task.L_L) hbt.task.L_L(handle);
            } else {
              if (hbt.task.R_L) hbt.task.R_L(handle);
            }
          }
        }
      } else {
        if (hbt.task.M_L) hbt.task.M_L(handle);
      }
      lt = hbt.time.now;
    }
  }
}
